﻿/*
创建日期:  2015.8.18
创建者:    张存
邮箱:      zhangcunliang@126.com
说明:
    
修改记录: 
    2020.11.14 将 缓存属性列表使用List 不再使用 Dictionary
 */
using System;
using System.Collections.Generic;
using System.Linq;

namespace ZhCun.DbCore.Entitys
{
    public abstract class EntityAnaly : IEntityAnaly
    {
        static readonly object _LockObj1 = new object();
        static readonly object _LockObj2 = new object();
        static readonly object LockObj_TableNameCache = new object();
        /// <summary>
        /// 实体类缓存,静态变量是保存为了减少反射次数
        /// </summary>
        static Dictionary<Type, List<EntityAttribute>> _ModelAttributeCache { get; } = new Dictionary<Type, List<EntityAttribute>>();
        /// <summary>
        /// 表名的缓存列表,获取后不再重新反射获取
        /// </summary>
        static Dictionary<Type, string> _TableNameCache;

        /// <summary>
        /// 实体类缓存,静态变量是保存为了减少反射次数
        /// </summary>
        protected Dictionary<Type, List<EntityAttribute>> ModelAttributeCache
        {
            get
            {
                return _ModelAttributeCache;
            }
        }
        /// <summary>
        /// 获取Model的属性对象,获取第一次后会放入一个缓存列表中
        /// 即只反射一次
        /// </summary>
        protected List<EntityAttribute> GetEntityAttribute<T>() where T : EntityBase, new()
        {
            Type t = typeof(T);
            if (!ModelAttributeCache.ContainsKey(t))
            {
                lock (_LockObj2)
                {
                    if (!ModelAttributeCache.ContainsKey(t))
                    {
                        var attrs = GetAttribute<T>();
                        ModelAttributeCache[t] = attrs;                   
                    }
                }
            }
            return ModelAttributeCache[t];
        }
        /// <summary>
        /// 通过解析获得Model的对象的参数,Key:为类的属性名
        /// </summary>
        /// <returns>返回model参数</returns>
        protected abstract List<EntityAttribute> GetAttribute<T>() where T : EntityBase, new();
        /// <summary>
        /// 根据Model类型获取表名
        /// </summary>
        public abstract string GetTableNameMy<TEntity>() where TEntity : EntityBase, new();
        /// <summary>
        /// 获取表名,
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <returns></returns>
        public string GetTableName<TEntity>() where TEntity : EntityBase, new()
        {
            if (_TableNameCache == null)
            {
                _TableNameCache = new Dictionary<Type, string>();
            }
            Type type = typeof(TEntity);

            if (!_TableNameCache.ContainsKey(type))
            {
                lock (LockObj_TableNameCache)
                {
                    if (!_TableNameCache.ContainsKey(type))
                    {
                        string tableName = GetTableNameMy<TEntity>();
                        _TableNameCache.Add(type, tableName);
                    }
                }
            }

            return _TableNameCache[type];
        }
        /// <summary>
        /// 根据对象的属性名称,反射获取到属性值
        /// </summary>
        public virtual object GetPropertyValue<TEntity>(TEntity entity, string propertyName) where TEntity : EntityBase, new()
        {
            object obj = Reflection.GetPropertyValue(entity, propertyName);
            return obj;
        }
        /// <summary>
        /// 获取所有映射的字段 如果指定了 IsNotField = true 则不会返回
        /// </summary>
        public string[] GetAllFields<TEntity>() where TEntity : EntityBase, new()
        {
            var attr = GetEntityAttribute<TEntity>();
            return attr.Select(s => s.ColumnName).ToArray();
        }

        public EntityAttribute GetAttribute<TEntity>(string propertyName) where TEntity : EntityBase, new()
        {
            var attr = GetEntityAttribute<TEntity>();
            return attr.Find(s => s.ColumnName == propertyName);
        }

        public string[] GetPrimaryKey<TEntity>() where TEntity : EntityBase, new()
        {
            var attr = GetEntityAttribute<TEntity>();
            attr.FindAll(s => s.IsPrimaryKey).ToArray();
            var pkColumns = attr.Where(s => s.IsPrimaryKey).Select(s => s.ColumnName).ToArray();
            if (pkColumns == null || pkColumns.Length == 0)
            {
                var pkName = attr.First().ColumnName;
                return new[] { pkName };
            }
            return pkColumns;
        }
    }
}